package it.koutifaris.travianmap.ui;

import it.koutifaris.travianmap.ui.PointToSquareHelper.SquareSizeSource;
import it.koutifaris.travianmap.ui.viewstate.DynamicViewState;
import it.koutifaris.travianmap.ui.viewstate.ViewStateImpl;
import it.koutifaris.travianmap.ui.viewstate.ViewStateSource;

import java.util.Iterator;

public class SquaredViewportBounds {

	private final PointToSquareHelper pointToSquareHelper;
	private final ViewStateSource viewStateSource;

	public SquaredViewportBounds(ViewStateSource viewStateSource, PointToSquareHelper pointToSquareHelper) {
		this.viewStateSource = viewStateSource;
		this.pointToSquareHelper = pointToSquareHelper;
	}

	SquaredViewportBounds(final ViewStateImpl viewState) {
		pointToSquareHelper = new PointToSquareHelper(new SquareSizeSource() {

			@Override
			public int getSquareSize() {
				return viewStateSource.getViewState().getSquareSize();
			}
		});

		viewStateSource = new ViewStateSource() {

			@Override
			public ViewStateImpl getViewState() {
				return viewState;
			}
		};
	}

	public int getX() {
		return pointToSquareHelper.getSquare(getViewState().getX());
	}

	public int getY() {
		return pointToSquareHelper.getSquare(getViewState().getY());
	}

	public int getWidth(int viewPortWidth) {
		return pointToSquareHelper.getSquare(viewPortWidth) + 1;
	}

	public int getHeight(int viewPortHeight) {
		return pointToSquareHelper.getSquare(viewPortHeight) + 1;
	}

	public Iterator<Integer> xIterator(int viewportWidth) {
		int end = this.getX() + this.getWidth(viewportWidth);
		return new BoundIterator(this.getX(), end);
	}

	public Iterator<Integer> yIterator(int viewportHeight) {
		int end = this.getY() + this.getHeight(viewportHeight);
		return new BoundIterator(this.getY(), end);
	}

	private DynamicViewState getViewState() {
		return viewStateSource.getViewState();
	}

	private static class BoundIterator implements Iterator<Integer> {

		private final int end;
		private int index;

		public BoundIterator(int start, int end) {
			this.end = end;
			this.index = start;
		}

		@Override
		public boolean hasNext() {
			return index <= end;
		}

		@Override
		public Integer next() {
			return index++;
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException();
		}

	}
}
